/**
 * DOM模块 - 提供DOM操作相关的工具函数
 * 兼容浏览器环境检查，服务端渲染时优雅降级
 */

/**
 * 检查是否在浏览器环境
 * @returns {boolean} 是否在浏览器环境
 */
function isBrowser() {
  return typeof window !== 'undefined' && typeof document !== 'undefined';
}

/**
 * 设置元素透明度
 * @param {HTMLElement} elem 元素
 * @param {number} level 透明度级别 (0-100)
 */
export function setOpacity(elem, level) {
  if (!isBrowser() || !elem || typeof level !== 'number') return;

  const opacity = Math.max(0, Math.min(100, level)) / 100;

  // 现代浏览器
  elem.style.opacity = opacity;

  // IE8及以下兼容
  if (elem.filters) {
    elem.style.filter = `alpha(opacity=${Math.round(opacity * 100)})`;
    elem.style.zoom = 1; // 触发IE的hasLayout
  }
}

/**
 * 图片转Base64
 * @param {HTMLImageElement|string} img 图片元素或图片URL
 * @param {string} format 输出格式
 * @param {number} quality 质量 (0-1)
 * @returns {Promise<string>} Base64字符串
 */
export function imageToBase64(img, format = 'image/png', quality = 0.92) {
  if (!isBrowser()) {
    return Promise.reject(new Error('imageToBase64 only works in browser environment'));
  }

  return new Promise((resolve, reject) => {
    let imageElement;

    if (typeof img === 'string') {
      imageElement = new Image();
      imageElement.crossOrigin = 'anonymous';
      imageElement.onload = () => processImage(imageElement);
      imageElement.onerror = () => reject(new Error('Failed to load image'));
      imageElement.src = img;
    } else if (img instanceof HTMLImageElement) {
      if (img.complete) {
        processImage(img);
      } else {
        img.onload = () => processImage(img);
        img.onerror = () => reject(new Error('Failed to load image'));
      }
    } else {
      reject(new Error('Invalid image parameter'));
    }

    function processImage(imageEl) {
      try {
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');

        canvas.width = imageEl.naturalWidth || imageEl.width;
        canvas.height = imageEl.naturalHeight || imageEl.height;

        ctx.drawImage(imageEl, 0, 0);

        const dataURL = canvas.toDataURL(format, quality);
        resolve(dataURL);
      } catch (error) {
        reject(error);
      }
    }
  });
}

/**
 * 实时显示时间
 * @param {HTMLElement} element 显示时间的元素
 * @param {string} format 时间格式
 */
export function showRealTime(element, format = 'YYYY年MM月DD日 HH时mm分ss秒') {
  if (!isBrowser() || !element) return;

  function updateTime() {
    const now = new Date();
    const timeString = formatTime(now, format);
    element.textContent = '现在是' + timeString;
  }

  // 立即更新一次
  updateTime();

  // 每秒更新
  const timer = setInterval(updateTime, 1000);

  // 返回清理函数
  return () => clearInterval(timer);
}

/**
 * 验证码倒计时
 * @param {HTMLButtonElement|HTMLInputElement} element 按钮元素
 * @param {Object} options 配置选项
 */
export function countdownTimer(element, options = {}) {
  if (!isBrowser() || !element) return;

  const {
    duration = 60,
    interval = 1000,
    activeText = '秒后重试',
    inactiveText = '发送验证码',
    // eslint-disable-next-line no-empty-function
    onStart = function() {},
    // eslint-disable-next-line no-empty-function
    onTick = function() {},
    // eslint-disable-next-line no-empty-function
    onEnd = function() {}
  } = options;

  let timeLeft = duration;
  let timer = null;

  function start() {
    if (timer) return; // 防止重复启动

    element.disabled = true;
    onStart();

    timer = setInterval(() => {
      timeLeft--;
      element.textContent = timeLeft + activeText;
      onTick(timeLeft);

      if (timeLeft <= 0) {
        stop();
      }
    }, interval);
  }

  function stop() {
    if (timer) {
      clearInterval(timer);
      timer = null;
    }

    element.disabled = false;
    element.textContent = inactiveText;
    timeLeft = duration;
    onEnd();
  }

  // 绑定点击事件
  element.addEventListener('click', start);

  // 返回控制对象
  return {
    start,
    stop,
    reset: () => {
      stop();
      timeLeft = duration;
    }
  };
}

/**
 * 滚动到指定元素
 * @param {HTMLElement|string} target 目标元素或选择器
 * @param {Object} options 滚动选项
 */
export function scrollTo(target, options = {}) {
  if (!isBrowser()) return;

  // 平滑滚动polyfill辅助函数
  function step(startY, distance, duration, startTime, timestamp) {
    if (!startTime) startTime = timestamp;
    const progress = Math.min((timestamp - startTime) / duration, 1);

    window.scrollTo(0, startY + distance * easeInOutCubic(progress));

    if (progress < 1) {
      requestAnimationFrame((ts) => step(startY, distance, duration, startTime, ts));
    }
  }

  const {
    behavior = 'smooth',
    _block = 'start',
    _inline = 'nearest',
    offset = 0
  } = options;

  let element;
  if (typeof target === 'string') {
    element = document.querySelector(target);
  } else if (target instanceof HTMLElement) {
    element = target;
  }

  if (!element) return;

  const rect = element.getBoundingClientRect();
  const scrollTop = window.pageYOffset + rect.top + offset;

  if ('scrollBehavior' in document.documentElement.style) {
    window.scrollTo({
      top: scrollTop,
      behavior
    });
  } else {
    // 降级处理：平滑滚动polyfill
    const startY = window.pageYOffset;
    const distance = scrollTop - startY;
    const duration = 500;

    requestAnimationFrame((timestamp) => step(startY, distance, duration, null, timestamp));
  }
}

/**
 * 复制文本到剪贴板
 * @param {string} text 要复制的文本
 * @returns {Promise<boolean>} 复制结果
 */
export function copyToClipboard(text) {
  if (!isBrowser()) {
    return Promise.resolve(false);
  }

  // 现代浏览器
  if (navigator.clipboard && window.isSecureContext) {
    return navigator.clipboard.writeText(text)
      .then(() => true)
      .catch(() => false);
  }

  // 降级处理
  return new Promise((resolve) => {
    const textArea = document.createElement('textarea');
    textArea.value = text;
    textArea.style.position = 'fixed';
    textArea.style.left = '-999999px';
    textArea.style.top = '-999999px';

    document.body.appendChild(textArea);
    textArea.focus();
    textArea.select();

    try {
      const result = document.execCommand('copy');
      resolve(result);
    } catch (error) {
      resolve(false);
    } finally {
      document.body.removeChild(textArea);
    }
  });
}

/**
 * 监听元素可见性变化
 * @param {HTMLElement|string} target 目标元素或选择器
 * @param {Function} callback 回调函数
 * @param {Object} options IntersectionObserver选项
 * @returns {Function} 取消监听函数
 */
export function observeVisibility(target, callback, options = {}) {
  if (!isBrowser() || !('IntersectionObserver' in window)) {
    // eslint-disable-next-line no-empty-function
    return function() {}; // 返回空函数
  }

  let element;
  if (typeof target === 'string') {
    element = document.querySelector(target);
  } else if (target instanceof HTMLElement) {
    element = target;
  }

  if (!element || typeof callback !== 'function') {
    // eslint-disable-next-line no-empty-function
    return function() {};
  }

  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      callback(entry.isIntersecting, entry);
    });
  }, options);

  observer.observe(element);

  return () => observer.disconnect();
}

/**
 * 获取元素样式
 * @param {HTMLElement} element 元素
 * @param {string} property 样式属性
 * @returns {string} 样式值
 */
export function getStyle(element, property) {
  if (!isBrowser() || !element) return '';

  if (window.getComputedStyle) {
    return window.getComputedStyle(element, null).getPropertyValue(property);
  } else if (element.currentStyle) {
    // IE8及以下
    return element.currentStyle[property.replace(/-(\w)/g, (match, letter) => letter.toUpperCase())];
  }

  return element.style[property] || '';
}

/**
 * 设置元素样式
 * @param {HTMLElement} element 元素
 * @param {string|Object} property 样式属性或样式对象
 * @param {string} value 样式值
 */
export function setStyle(element, property, value) {
  if (!isBrowser() || !element) return;

  if (typeof property === 'object') {
    Object.keys(property).forEach(key => {
      element.style[key] = property[key];
    });
  } else if (typeof property === 'string') {
    element.style[property] = value;
  }
}

/**
 * 检查元素是否在视口中
 * @param {HTMLElement} element 元素
 * @param {number} threshold 阈值 (0-1)
 * @returns {boolean} 是否在视口中
 */
export function isElementInViewport(element, threshold = 0) {
  if (!isBrowser() || !element) return false;

  const rect = element.getBoundingClientRect();
  const windowHeight = window.innerHeight || document.documentElement.clientHeight;
  const windowWidth = window.innerWidth || document.documentElement.clientWidth;

  const verticalVisible = (rect.top + rect.height * threshold) <= windowHeight &&
                          (rect.bottom - rect.height * threshold) >= 0;

  const horizontalVisible = (rect.left + rect.width * threshold) <= windowWidth &&
                            (rect.right - rect.width * threshold) >= 0;

  return verticalVisible && horizontalVisible;
}

/**
 * 格式化时间（内部使用）
 * @param {Date} date 日期对象
 * @param {string} format 格式字符串
 * @returns {string} 格式化后的时间
 */
function formatTime(date, format) {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  const hour = String(date.getHours()).padStart(2, '0');
  const minute = String(date.getMinutes()).padStart(2, '0');
  const second = String(date.getSeconds()).padStart(2, '0');

  return format
    .replace('YYYY', year)
    .replace('MM', month)
    .replace('DD', day)
    .replace('HH', hour)
    .replace('mm', minute)
    .replace('ss', second);
}

/**
 * 缓动函数
 * @param {number} t 时间进度 (0-1)
 * @returns {number} 缓动值
 */
function easeInOutCubic(t) {
  return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
}
